#include "Entity.h"
#include "Entity_List.h"
#include "../World/Pathfinding.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Zahl der vorhandenen Entity's */
int Entity_Number;

/* Alle Entity's setzten */
struct sEntity Entity[ Entity_Max ];

int Entity_Init()
{
    int iN;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        /* Nummer setzen */
        Entity[iN].Num = iN;

        /* Achse reseten */
        Entity[iN].X = 0;
        Entity[iN].Y = 0;
        Entity[iN].Z = 0;

        /* Leben setzten */
        Entity[iN].Live = 0;

        /* Keine veränderung */
        Entity[iN].Change = 0;

        /* Funktion setzten */
        Entity[iN].Process = 0;

        /* Animation_Speed */
        Entity[iN].Animation_Speed = 2;

        /* Energy */
        Entity[iN].Energy = 0;

        /* Was er tut */
        Entity[iN].WorkProcess = 0;
    }

    //printf("%d\n", sizeof(Entity));
    logDebug("Entity size: %.0f kB", (float)sizeof(Entity)/1024);
    return sizeof(Entity);
}

struct sEntity *Entity_Create(int X, int Y, int Live, int Process)
{
    int iN, iN_Free;

    iN_Free = -1;

    /* Suchen nach einem leeren Entity */
    for(iN = 0; iN < Entity_Max; iN++)
    {
        /* Tote überspringen */
        if(Entity[iN].Live) continue;

        /* Gefunden */
        iN_Free = iN;

        break;
    }

    if(iN_Free == -1)
        return &Entity[0];

    /* Wer weiß ob es kapput ist */
    Entity_Remove(&Entity[iN_Free]);

    Entity[iN_Free].X = (int)X;
    Entity[iN_Free].Y = (int)Y;
    Entity[iN_Free].Live = (int)Live;
    Entity[iN_Free].Process = Process;
    Entity[iN_Free].Change = 2;

    //printf("Ok %d\n", iN_Free);

    return &Entity[iN_Free];
}

#define ENTITY_DISTANCE_TYPE 1

int Entity_Distance(int X, int Y, int X2, int Y2)
{
    int Distx;
    int Disty;

    switch(ENTITY_DISTANCE_TYPE)
    {
        case 0:
            if ( X >= X2 )  Distx = X-X2;
            else Distx = X2-X;
            if (Y >= Y2)  Disty = Y-Y2;
            else  Disty = Y2-Y;
            return sqrt( (Distx*Distx) + (Disty*Disty) );
        break;
        case 1:
            return sqrt( (X-X2)*(X-X2)+(Y-Y2)*(Y-Y2));
        break;
        case 2:
            return sqrt( pow((X-X2), 2) + pow((Y-Y2), 2) );
        break;
    }
}

int Entity_FindRadius( int X, int Y, int Process, int Radius)
{
    int iN;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        if(Entity_Distance( X, Y, Entity[iN].X, Entity[iN].Y) < Radius)
            if( Entity[iN].Process == Process )
                return Entity[iN].Num;
    }
    return -1;
}

int Entity_FindRadiusNear( int X, int Y, int Process, int Radius)
{
    int iN;
    int iN_Return = -1;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        if(Entity_Distance( X, Y, Entity[iN].X, Entity[iN].Y) < Radius)
            if( Entity[iN].Process == Process )
            {
                if( iN_Return+1 )
                {
                    if( (Entity_Distance( X, Y, Entity[iN_Return].X, Entity[iN_Return].Y)) >
                        (Entity_Distance( X, Y, Entity[iN].X, Entity[iN].Y)) )
                            iN_Return = iN;
                }
                else
                    iN_Return = iN;
            }
    }
    return iN_Return;
}

void Entity_Walk(struct sEntity *Target, struct sEntity *Obj)
{
    int X,Y;

    /* Zu Nah */
    /*if(Entity_Distance( (int)Target->X, (int)Target->Y, (int)Obj->X, (int)Obj->Y) < 5 )
        return;*/

    /* X & Y achse */
    X = Target->X;
    Y = Target->Y;

    double Erg = atan2( X - (int)Obj->X, Y- (int)Obj->Y);
    double grad = Erg*180/3.14;

    Obj->X += (float)sin_d(grad)*4;
    Obj->Y += (float)cos_d(grad)*4;

    Obj->R = grad;
    return;
}

/*int Entity_FindCollison( int iN_Self, int Process)
{
    int iN;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        if(Entity_Collision(iN, iN_Self))
            if( Entity[iN].Process == Process )
                return Entity[iN].Num;
    }
    return -1;
}*/

struct sEntity *Entity_Get( int iN )
{
    return(&Entity[ iN ]);
}

Uint32 Entity_Process(Uint32 intervall, void *parameter)
{
    int iN;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        /* Tote überspringen */
        if(!Entity[iN].Live) continue;

        /* Process durchführen */
        Entity_List( &Entity[iN] );

        //Graphic_Point( Entity[iN].X,  Entity[iN].Y, 1);

        /* Rand errecht? richtung ändern */

        //if(Entity_Distance( Entity[iN].X,  Entity[iN].Y, 0, 0) > Entity_Border_Max)
        if(Entity[iN].X < 0)
            Entity[iN].X = 0;
        if(Entity[iN].Y < 0)
            Entity[iN].Y = 0;

        if(!Entity[iN].Live)
            Entity_Remove(&Entity[iN]);
    }
    return intervall;
}

void Entity_Process_Graphic()
{
    int iN;

    for(iN = 0; iN < Entity_Max; iN++)
    {
        /* Tote überspringen */
        if(!Entity[iN].Live) continue;

        /* Process durchführen */
        Entity_List_Graphic( &Entity[iN] );

        if(!Entity[iN].Live)
            Entity_Remove(&Entity[iN]);
    }
    return;
}

void Entity_Remove( struct sEntity *Obj )
{
    if( !Obj->Live )
        return;

    /* Das hat zeit gebraucht^^ */
    Obj->X = 0;
    Obj->Y = 0;
    Obj->Z = 0;
    Obj->R = 0;
    Obj->Energy = 0;
    Obj->Process = 0;
    Obj->Live = 0;
    Obj->Team = 0;

    /* Rücksetzten von AttachNum */
    Entity_Get(Obj->AttachNum-1)->Work = 0;
    Entity_Get(Obj->AttachNum-1)->AttachNum = 0;
    Obj->AttachNum = 0;
    Obj->Work = 0;

    Obj->Change = 2;
    Obj->WorkProcess = 0;
}


void Entity_None( struct sEntity *Obj )
{
    /* Leben auf Null setzten */
    Obj->Live = 0;

    /* Dies ist ein Fehler -> Melden */
    printf("Error: Das Obj %d wurde nicht richtig gelöscht!\n", Obj->Num);
}

void Entity_Border( struct sEntity *Obj )
{
    if(Obj->X != 0 || Obj->Y != 0)
    {
        /* Achse setzten */
        Obj->X = 0;
        Obj->Y = 0;

        /* Es hat sich was gändert */
        Obj->Change = 1;
    }
}

void Entity_CmdMove( struct sEntity *Obj, float XTarget, float YTarget ) {
    Obj->XTarget = XTarget;
    Obj->YTarget = YTarget;

    Obj->nextWp = findPath( Obj->X, Obj->Y, XTarget, YTarget );
}



